package com.yami.shop.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.dto.RedPackerIsUnpack;
import com.yami.shop.bean.dto.red.RedPacketBasic;
import com.yami.shop.bean.dto.red.RedPacketInfoDto;
import com.yami.shop.bean.enums.SceneType;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.vo.RedPacketInfoVo;
import com.yami.shop.bean.vo.RedPacketVo;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.response.ServerResponseEntity;
import com.yami.shop.common.util.DataWebService;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.config.ShopConfig;
import com.yami.shop.dao.RedPacketInfoMapper;
import com.yami.shop.service.*;
import com.yami.shop.util.RedPacketUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.yami.shop.util.RedPacketUtils.*;

@Service
@Slf4j
public class RedPacketInfoServiceImpl extends ServiceImpl<RedPacketInfoMapper, RedPacketInfo> implements RedPacketInfoService {

    @Autowired
    private RedPacketRecordService redPacketRecordService;
    @Autowired
    private ChannelUserRelationRecordService channelUserRelationRecordService;

    @Autowired
    private OrderService orderService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ShopConfig shopConfig;
    @Autowired
    private DataWebService dataWebService;
    @Autowired
    private ProdNftService prodNftService;
    @Autowired
    private ProductService productService;
    @Autowired
    private MeltCloudUserRemarkService userRemarkService;
    /**
     * 红包记录
     *
     * @param redPacketId
     * @param channelUserId
     * @return
     */
    @Override
    public RedPacketVo records(Long redPacketId, String channelUserId) {
        RedPacketVo records = baseMapper.records(redPacketId);
        if(ObjectUtil.isNotEmpty(records.getProdId())){
            Product productByProdId = productService.getProductByProdId(records.getProdId());
            records.setDawName(productByProdId.getProdName());
            records.setDawImag(productByProdId.getPic());
        }
        return records;
    }

    /**
     * 发送红包
     *
     * @param redPacketInfoDto
     */
    @Override
    public RedPacketVo sendRedPacket(RedPacketInfoDto redPacketInfoDto) {
        if(ObjectUtils.isEmpty(redPacketInfoDto.getTotalPacket())){
            redPacketInfoDto.setTotalPacket(1);
        }
        // 保存红包记录
        RedPacketInfo redPacketInfo = BeanUtil.copyProperties(redPacketInfoDto, RedPacketInfo.class);
        redPacketInfo.setRemainingPacket(redPacketInfo.getTotalPacket());
        redPacketInfo.setRemainingAmount(redPacketInfo.getTotalAmount());
        this.save(redPacketInfo);

        RedPacketVo redPacketVo = RedPacketVo.builder()
                .redPacketId(redPacketInfo.getId())
                .title(redPacketInfo.getTitle())
                .type(redPacketInfo.getType())
                .build();
        RedPacketBasic redPacketBasic = RedPacketBasic
                .builder()
                .totalPacket(redPacketInfo.getTotalPacket())
                .totalAmount((int)(redPacketInfo.getTotalAmount() * 100))
                .build();
        // 抢红包资格缓存
        redisTemplate.opsForValue().set(GRAB_RED_PACKAGE_KEY + redPacketInfo.getId(), redPacketBasic.getTotalAmount(), RedPacketUtils.RED_PACKET_EXPIRE, TimeUnit.SECONDS);

        // 红包个数和总金额存入缓存
        redisTemplate.opsForValue().set(RED_PACKAGE_KEY + redPacketInfo.getId(), redPacketBasic, RedPacketUtils.RED_PACKET_EXPIRE, TimeUnit.SECONDS);

        return redPacketVo;
    }

    @Override
    public RedPacketInfo getMaxCrtTimeByUserId(String userId) {
        return baseMapper.getMaxCrtTimeByUserId(userId);
    }

    /**
     * 获取抢红包资格 群
     *
     * @param redPacketId
     * @param userId
     * @return
     */
    @Override
    public synchronized ServerResponseEntity<RedPackerIsUnpack> rodRedPacket(Long redPacketId, String userId) {
        // status 0：可以领取1：领取过2：没领取过3：领完了
        RedPackerIsUnpack redPackerIsUnpack = new RedPackerIsUnpack();
        // 1、红包过期
        RedPacketInfo packetInfo = this.getById(redPacketId);
        if("1".equals(packetInfo.getType())){
            // 判断是否绑定链
            Boolean hasDTCAddress = channelUserRelationRecordService.isHasAllAddress(userId, packetInfo.getChainCode(), packetInfo.getChannelCode(),packetInfo.getType());
            redPackerIsUnpack.setIsHasDTCAddress(hasDTCAddress);
            if(!hasDTCAddress){
//                return ServerResponseEntity.showFailMsg(I18nMessage.getMessage("yami.dtc.redpacket.open.check"));
                redPackerIsUnpack.setChannelCode(packetInfo.getChannelCode());
                redPackerIsUnpack.setChain(packetInfo.getChainCode());
                redPackerIsUnpack.setChainType(packetInfo.getChainType());
                return ServerResponseEntity.success(redPackerIsUnpack);
            }
        }
        if(packetInfo.getStatus() == 2){
            LambdaQueryWrapper<RedPacketRecord> eq = new LambdaQueryWrapper<RedPacketRecord>()
                    .eq(RedPacketRecord::getRedPacketId, redPacketId)
                    .eq(RedPacketRecord::getUserId, userId)
                    .ne(RedPacketRecord::getRecType,2);
            RedPacketRecord one = redPacketRecordService.getOne(eq);
            if(ObjectUtil.isEmpty(one)){
                redPackerIsUnpack.setIsUnpack(false);
                redPackerIsUnpack.setStatus(2);
            }else{
                redPackerIsUnpack.setIsUnpack(true);
                redPackerIsUnpack.setStatus(1);
            }
        }else{
            // 2. 验证这个人是否抢过红包
            Object redPackage = redisTemplate.opsForHash().get(RED_PACKAGE_CONSUME_KEY + redPacketId, userId);
            if (ObjectUtil.isNotEmpty(redPackage)) {
                redPackerIsUnpack.setIsUnpack(true);
                redPackerIsUnpack.setStatus(1);
            }else{
                redPackerIsUnpack.setIsUnpack(false);
                // 3. 验证这个红包还有剩余
                RedPacketBasic redPacketBasic = (RedPacketBasic)redisTemplate.opsForValue().get(RED_PACKAGE_KEY + redPacketId);
                if (ObjectUtil.isEmpty(redPacketBasic) || redPacketBasic.getTotalPacket() <= 0) {
                    redPackerIsUnpack.setStatus(3);
                    LambdaQueryWrapper<RedPacketRecord> eq = new LambdaQueryWrapper<RedPacketRecord>()
                            .eq(RedPacketRecord::getRedPacketId, redPacketId)
                            .eq(RedPacketRecord::getUserId, userId)
                            .ne(RedPacketRecord::getRecType, 2);
                    RedPacketRecord one = redPacketRecordService.getOne(eq);
                    if(ObjectUtil.isNotEmpty(one)){
                        redPackerIsUnpack.setIsUnpack(true);
                        redPackerIsUnpack.setStatus(1);
                    }else{
                        redPackerIsUnpack.setStatus(3);
                    }
                }else{
                    redPackerIsUnpack.setStatus(0);
                }
            }
        }
        return ServerResponseEntity.success(redPackerIsUnpack);
    }

    /**
     * 获取抢红包资格 单聊
     *
     * @param redPacketId
     * @param userId
     * @return
     */
    @Override
    public synchronized ServerResponseEntity<Boolean> rodOneRedPacket(Long redPacketId, String userId) {
        LambdaQueryWrapper<RedPacketRecord> eq = new LambdaQueryWrapper<RedPacketRecord>()
                .eq(RedPacketRecord::getRedPacketId, redPacketId);
        RedPacketRecord one = redPacketRecordService.getOne(eq);
        if (ObjectUtil.isEmpty(one)) {
            return ServerResponseEntity.success(false);
        }else{
            return ServerResponseEntity.success(true);
        }
    }


    /**
     * 打开红包
     *
     * @param redPacketId
     * @param userId
     * @param type        红包类型 0:人民币红包 1:DAW红包 2:Gas红包
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public synchronized Double unpackRedPacket(Long redPacketId, String userId, String type) {
        // 1. 打开红包
        RedPacketInfo packetInfo = this.getById(redPacketId);
        // 剩余红包金额
        Double remainingAmount = packetInfo.getRemainingAmount();
        // 剩余红包个数
        Integer remainingPacket = packetInfo.getRemainingPacket();
        if (remainingAmount > 0) {
            // 二倍均值法: 剩余红包金额/剩余红包个数*2
            Double[] bigDecimals = clickRedPacket(remainingAmount, remainingPacket);
            if (bigDecimals.length > 0) {
                Double amount = bigDecimals[0];
                //3.记录本次拆红包
                RedPacketRecord redPacketRecord = RedPacketRecord.builder().redPacketId(packetInfo.getId()).amount(amount).createTime(LocalDateTime.now()).userId(userId).build();
                redPacketRecordService.save(redPacketRecord);
                //4.修改红包剩余金额
                double value = remainingAmount - amount;
                packetInfo.setRemainingAmount(value);
                packetInfo.setRemainingPacket(packetInfo.getRemainingPacket() - 1);
                this.updateById(packetInfo);
                return amount;
            }
        }
        return 0D;
    }

    /**
     * 模拟抢红包，使用二倍均值法
     *
     * @param money  总金额，单位：分
     * @param person 抢红包人数
     * @return 生成的红包金额数组
     */
    public Double[] clickRedPacket(Double money, int person) {
        Double[] amountArr = new Double[person];
        System.out.printf("%s 元钱 分给 %s 人\n", money, person);
        for (int i = 0; i < amountArr.length - 1; i++) {
            double avgAmount = money / person;
            double doubleAvgAmount = avgAmount * 2;
            person--;
            int min = 1;
            double max = doubleAvgAmount;
            Double currentAmount = getRandomBetween(min, max);
            amountArr[i] = currentAmount;
            money = money - currentAmount;
            System.out.printf("剩余人数：%s\t抢到：%s \t剩余金额：%s\t本次均值的二倍：%s\t金额随机范围：[%s, %s]\n", person, currentAmount, money, doubleAvgAmount, min, max);
        }
        amountArr[amountArr.length - 1] = money;
        return amountArr;
    }

    /**
     * 获取指定区间内的随机数，区间：[a, b) 左开右闭
     */
    public Double getRandomBetween(int a, double b) {
        double newScoppe = Math.random() * (b - a);
        return (Math.floor(a + newScoppe));
    }

    /**
     * 收到的红包列表
     *
     *
     * @param page
     * @param userId
     * @param type
     * @param year
     * @return
     */
    @Override
    public IPage<RedPacketInfoVo> getRedPackets(PageParam<RedPacketInfoVo> page, String userId, String type, String year) {

        IPage<RedPacketInfoVo> redPackets = baseMapper.getRedPackets(page, userId, type, year);
        redPackets.getRecords().forEach(s->{
            s.getUserRecords().forEach(redPacketInfoUserVo -> {
                // 获取用户备注
                QueryWrapper<MeltCloudUserRemark> meltCloudUserRemarkQueryWrapper = new QueryWrapper<>();
                meltCloudUserRemarkQueryWrapper.eq("type",1);
                meltCloudUserRemarkQueryWrapper.eq("user_id",userId);
                meltCloudUserRemarkQueryWrapper.eq("obj_id",redPacketInfoUserVo.getUserId());
                meltCloudUserRemarkQueryWrapper.last("limit 1");
                MeltCloudUserRemark one = userRemarkService.getOne(meltCloudUserRemarkQueryWrapper);
                if(ObjectUtil.isNotEmpty(one)){
                    redPacketInfoUserVo.setUserName(one.getRemark());
                }
                if("1".equals(redPacketInfoUserVo.getType()) && ObjectUtil.isNotEmpty(redPacketInfoUserVo.getDenomId())){
                    // 获取商品名称
                    ProdNft dataByDenomId = prodNftService.getDataByDenomId(redPacketInfoUserVo.getDenomId());
                    if(ObjectUtil.isNotEmpty(dataByDenomId)){
                        Product productById = productService.getProductById(dataByDenomId.getProdId());
                        if(ObjectUtil.isNotEmpty(productById)){
                            redPacketInfoUserVo.setDawName(productById.getProdName());
                        }
                    }
                }
            });
        });
        return redPackets;
    }

    /**
     * 发出的红包列表
     *
     *
     * @param page
     * @param userId
     * @param type
     * @param year
     * @return
     */
    @Override
    public IPage<RedPacketInfoVo> sendRedPackets(PageParam<RedPacketInfoVo> page, String userId, String type, String year) {
        IPage<RedPacketInfoVo> redPacketInfoVoIPage = baseMapper.sendRedPackets(page, userId, type, year);
        // 获取 dawName
        redPacketInfoVoIPage.getRecords().forEach(s->{
            s.getUserRecords().forEach(redPacketInfoUserVo -> {
                if("1".equals(redPacketInfoUserVo.getType()) && ObjectUtil.isNotEmpty(redPacketInfoUserVo.getDenomId())){
                    // 获取商品名称
                    ProdNft dataByDenomId = prodNftService.getDataByDenomId(redPacketInfoUserVo.getDenomId());
                    if(ObjectUtil.isNotEmpty(dataByDenomId)){
                        Product productById = productService.getProductById(dataByDenomId.getProdId());
                        if(ObjectUtil.isNotEmpty(productById)){
                            redPacketInfoUserVo.setDawName(productById.getProdName());
                        }
                    }
                }
            });
        });
        // 获取 发出红包内容 总个数
        return redPacketInfoVoIPage;
    }

    /**
     * 根据用户id 和 红包id 查询金额
     *
     * @param redPacketId
     * @param userId
     * @return
     */
    @Override
    public  RedPacketRecord getRedAmount(Long redPacketId, String userId) {
        LambdaQueryWrapper<RedPacketRecord> eq = new LambdaQueryWrapper<RedPacketRecord>()
                .eq(RedPacketRecord::getRedPacketId, redPacketId)
                .eq(RedPacketRecord::getUserId, userId);
        RedPacketRecord one = redPacketRecordService.getOne(eq);
        return one;
    }

    @Override
    public IPage<RedPacketInfoVo> sendRedListByyears(String userId, String type, String year) {

        return null;
    }

    @Override
    public void saveRedPacketRecord(Long redPacketId, String userId, String type, Integer redPacketAmount, String xsUserId) {
        RedPacketInfo packetInfo = this.getById(redPacketId);
        // 剩余红包金额
        Double remainingAmount = packetInfo.getRemainingAmount();
        // 记录本次拆红包
        RedPacketRecord redPacketRecord = RedPacketRecord.builder()
                .redPacketId(redPacketId)
                .amount(packetInfo.getType().equals("0") ? redPacketAmount.doubleValue() / 100 : redPacketAmount.doubleValue())
//                .createTime(LocalDateTime.now())
                .userId(userId)
                .recType(packetInfo.getUserId().equalsIgnoreCase(userId) ? 3 : 1)
                .type(packetInfo.getType())
                .build();
        // 获取新生UserId
        redPacketRecord.setXsUserId(xsUserId);
        redPacketRecordService.save(redPacketRecord);
        // 修改红包剩余金额
        double value = remainingAmount - (packetInfo.getType().equals("0") ? redPacketAmount.doubleValue() / 100 : redPacketAmount.doubleValue());
        packetInfo.setRemainingAmount(value);
        packetInfo.setRemainingPacket(packetInfo.getRemainingPacket() - 1);

        this.updateById(packetInfo);
    }

    @Override
    @Transactional
    public RedPacketVo sendGasRedPacket(RedPacketInfoDto red) {
        // 1、保存红包记录
        RedPacketInfo redPacketInfo = BeanUtil.copyProperties(red, RedPacketInfo.class);
        redPacketInfo.setType("2");
        redPacketInfo.setStatus(1);
        redPacketInfo.setRemainingPacket(redPacketInfo.getTotalPacket());
        redPacketInfo.setRemainingAmount(red.getGasNum().doubleValue());
        redPacketInfo.setTotalAmount(red.getGasNum().doubleValue());
        this.save(redPacketInfo);
        RedPacketVo redPacketVo = RedPacketVo.builder()
                .redPacketId(redPacketInfo.getId())
                .title(redPacketInfo.getTitle())
                .type(redPacketInfo.getType())
                .build();
        // 抢红包资格缓存
        RedPacketBasic redPacketBasic = RedPacketBasic
                .builder()
                .totalPacket(redPacketInfo.getTotalPacket())
                .totalAmount(red.getGasNum())
                .build();
        redisTemplate.opsForValue().set(GRAB_RED_PACKAGE_KEY + redPacketInfo.getId(), redPacketBasic.getTotalAmount(), RedPacketUtils.RED_PACKET_EXPIRE, TimeUnit.SECONDS);

        // 红包个数和总金额存入缓存
        redisTemplate.opsForValue().set(RED_PACKAGE_KEY + redPacketInfo.getId(), redPacketBasic, RedPacketUtils.RED_PACKET_EXPIRE, TimeUnit.SECONDS);
        return redPacketVo;
    }

}
